package cn.bingoogolapple.bgabanner;

import ohos.agp.components.Component;
import ohos.agp.components.DependentLayout;
import ohos.agp.components.Image;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.utils.Pair;

import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;

/**
 * 作者:王浩 邮件:bingoogolapple@gmail.com
 * 创建时间:16/7/5 上午11:34
 * 描述:工具类
 *
 * @since 2021-04-19
 */
public class BGABannerUtil {
    private BGABannerUtil() {
    }

    /**
     * getItemImageView
     *
     * @param context
     * @param resId
     * @param localImageSize
     * @param scaleType
     * @return get item imageview
     */
    public static Image getItemImageView(Context context, int resId, BGALocalImageSize localImageSize, Image.ScaleMode scaleType) {
        Image imageView = new Image(context);
        DependentLayout.LayoutConfig layoutConfig = new DependentLayout.LayoutConfig(DependentLayout.LayoutConfig.MATCH_PARENT, DependentLayout.LayoutConfig.MATCH_PARENT);
        imageView.setLayoutConfig(layoutConfig);
        imageView.setPixelMap(getScaledImageFromResource(context, resId, localImageSize.getMaxWidth(), localImageSize.getMaxHeight(), localImageSize.getMinWidth(), localImageSize.getMinHeight()));
        imageView.setClickable(true);
        imageView.setScaleMode(scaleType);
        return imageView;
    }

    /**
     * resetPageTransformer
     *
     * @param views
     */
    public static void resetPageTransformer(List<? extends Component> views) {
        if (views == null) {
            return;
        }
        for (Component view : views) {
            view.setVisibility(Component.VISIBLE);
        }
    }

    /**
     * isIndexNotOutOfBounds
     *
     * @param position
     * @param collection
     * @return isCollectionNotEmpty
     */
    public static boolean isIndexNotOutOfBounds(int position, Collection collection) {
        return isCollectionNotEmpty(collection) && position < collection.size();
    }

    /**
     * isCollectionEmpty
     *
     * @param collection
     * @param args
     * @return check the collection is empty or not
     */
    public static boolean isCollectionEmpty(Collection collection, Collection... args) {
        if (collection == null || collection.isEmpty()) {
            return true;
        }
        for (Collection arg : args) {
            if (arg == null || arg.isEmpty()) {
                return true;
            }
        }
        return false;
    }

    /**
     * isCollectionNotEmpty
     *
     * @param collection
     * @param args
     * @return isCollectionNotEmpty
     */
    public static boolean isCollectionNotEmpty(Collection collection, Collection... args) {
        return !isCollectionEmpty(collection, args);
    }

    /**
     * 从资源获取 Bitmap
     * bitmap 的宽高在 maxWidth maxHeight 和 minWidth minHeight 之间
     *
     * @param context 上下文
     * @param resId id
     * @param maxWidth 最大宽度
     * @param maxHeight 最大高度
     * @param minWidth 最小宽度
     * @param minHeight 最小高度
     * @return 返回所有值
     */
    public static PixelMap getScaledImageFromResource(Context context, int resId, int maxWidth, int maxHeight, float minWidth, float minHeight) {
        LoadBitmapPair<Throwable> result;
        do {
            result = getImageFromResource(context, resId, maxWidth, maxHeight);
            maxWidth /= 2;
            maxHeight /= 2;
        } while (result != null && result.s instanceof OutOfMemoryError && maxWidth > minWidth && maxHeight > minHeight);

            return result.f;

    }

    /**
     * 从资源获取 Bitmap
     * bitmap 的宽高在 maxWidth maxHeight 和 minWidth minHeight 之间
     *
     * @param context 上下文
     * @param resId id
     * @param maxWidth 最大宽度
     * @param maxHeight 最大高度
     * @return 返回所有值
     */
    public static LoadBitmapPair<Throwable> getImageFromResource(Context context, int resId, int maxWidth, int maxHeight) {
        LoadBitmapPair<Throwable> result;
        ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions();
        sourceOptions.formatHint = "image/png";
        ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
        decodingOptions.desiredPixelFormat = PixelFormat.ARGB_8888;
        InputStream is = null;

        try {
            if (maxWidth == 0 && maxHeight == 0) {
                is = context.getResourceManager().getResource(resId);
                ImageSource source = ImageSource.create(is, sourceOptions);

                result = new LoadBitmapPair<>(source.createPixelmap(decodingOptions), null);
                is.close();
            } else {
                // If we have to resize this image, first get the natural bounds.
                decodingOptions.allowPartialImage = true;
                is = context.getResourceManager().getResource(resId);
                ImageSource elseSource = ImageSource.create(is, sourceOptions);
                elseSource.createPixelmap(decodingOptions);
                is.close();
                int actualWidth = elseSource.getImageInfo().size.width;
                int actualHeight = elseSource.getImageInfo().size.height;

                // Then compute the dimensions we would ideally like to decode to.
                int desiredWidth = getResizedDimension(maxWidth, maxHeight, actualWidth, actualHeight);
                int desiredHeight = getResizedDimension(maxHeight, maxWidth, actualHeight, actualWidth);

                // Decode to the nearest power of two scaling factor.
                decodingOptions.allowPartialImage = false;
                decodingOptions.sampleSize = calculateInSampleSize(elseSource, desiredWidth, desiredHeight);
                is = context.getResourceManager().getResource(resId);
                ImageSource imageSource = ImageSource.create(is, sourceOptions);
                PixelMap tempBitmap = imageSource.createPixelmap(decodingOptions);
                is.close();

                // If necessary, scale down to the maximal acceptable size.
                if (tempBitmap != null && (tempBitmap.getImageInfo().size.width > desiredWidth || tempBitmap.getImageInfo().size.height > desiredHeight)) {
                    result = new LoadBitmapPair<>(imageSource.createPixelmap(decodingOptions), null);
                    tempBitmap.release();
                } else {
                    result = new LoadBitmapPair<>(tempBitmap, null);
                }
            }
        } catch (OutOfMemoryError | IOException | NotExistException exception) {
            exception.fillInStackTrace();
            result = new LoadBitmapPair(null, exception);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.fillInStackTrace();
                }
            }
        }
        return result;
    }

    private static class LoadBitmapPair<S extends Throwable> extends Pair<PixelMap, S> {
        LoadBitmapPair(PixelMap first, S second) {
            super(first, second);
        }
    }

    /**
     * getResizedDimension
     *
     * @param maxPrimary
     * @param maxSecondary
     * @param actualPrimary
     * @param actualSecondary
     * @return the value of resized dimension
     */
    public static int getResizedDimension(int maxPrimary, int maxSecondary, int actualPrimary, int actualSecondary) {
        // If no dominant value at all, just return the actual.
        if (maxPrimary == 0 && maxSecondary == 0) {
            return actualPrimary;
        }

        // If primary is unspecified, scale primary to match secondary's scaling ratio.
        if (maxPrimary == 0) {
            double ratio = (double) maxSecondary / (double) actualSecondary;
            return (int) (actualPrimary * ratio);
        }

        if (maxSecondary == 0) {
            return maxPrimary;
        }

        double ratio = (double) actualSecondary / (double) actualPrimary;
        int resized = maxPrimary;
        if (resized * ratio > maxSecondary) {
            resized = (int) (maxSecondary / ratio);
        }
        return resized;
    }

    /**
     * calculateInSampleSize
     *
     * @param options
     * @param reqWidth
     * @param reqHeight
     * @return the value of insamplesize
     */
    public static int calculateInSampleSize(ImageSource options, int reqWidth, int reqHeight) {
        if (reqWidth == 0 || reqHeight == 0) {
            return 1;
        }

        // Raw height and width of image
        final int height = options.getImageInfo().size.height;
        final int width = options.getImageInfo().size.width;
        int inSampleSize = 1;
        if (height > reqHeight || width > reqWidth) {
            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }
        return inSampleSize;
    }

    /**
     * getImageFromResource
     *
     * @param context
     * @param resId
     * @return the pixelmap from resid
     */
    public static PixelMap getImageFromResource(Context context, int resId) {
        PixelMap pixelMap = null;
        ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions();
        sourceOptions.formatHint = "image/png";
        ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
        decodingOptions.desiredPixelFormat = PixelFormat.ARGB_8888;
        InputStream is = null;
        try {
            is = context.getResourceManager().getResource(resId);
            ImageSource source = ImageSource.create(is, sourceOptions);
            pixelMap = source.createPixelmap(decodingOptions);
            is.close();
        } catch (OutOfMemoryError | IOException | NotExistException exception) {
            exception.fillInStackTrace();
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.fillInStackTrace();
                }
            }
        }
        return pixelMap;
    }
}